﻿namespace SpeadFrm.Common.Utility
{
    public sealed class ExpressionUtil
    {
        private ExpressionUtil()
        {
            //
            // TODO: 在此处添加构造函数逻辑
            //
        }

        /// <summary>
        /// 判断表达式是否合法 合法的字符为数字，+，-，*，/，（，），%，或某一特定的字符：char ch.
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static bool IsExpressionsValid(string str, char ch)
        {
            int i = 0, bracketCount = 0;//判断括号的数量是否正确

            int len = str.Length;
            if (len == 0)
            {//表达式不能为空，否则也报错

                return false;
            }
            while (i < len)
            {
                if (i == 0)
                {//第一个字符的合法性

                    if (str[i] == '(')
                    {
                        bracketCount++;
                    }
                    if (str[i] != ch && str[i] != '(' && (str[i] > '9' || str[i] < '0'))
                    {
                        return false;
                    }
                }
                else if (i == len - 1)
                {
                    if (str[i] == ')')
                    {
                        bracketCount--;
                    }
                    if (str[i] != '%' && str[i] != ch && str[i] != ')' && (str[i] > '9' || str[i] < '0'))
                    {//对最后一个字符的合法性判断

                        return false;
                    }
                }
                else
                {//根据前面和后面的字符对在中间出现的每种字符做判断

                    if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/')
                    {//判断运算符的前后是否合法
                        if (str[i - 1] != ch && str[i - 1] != ')' && str[i - 1] != '%' && (str[i - 1] < '0' || str[i - 1] > '9'))
                        {//前面出现的只能是 ch, ), %, 数字
                            return false;
                        }
                        if (str[i + 1] != ch && str[i + 1] != '(' && (str[i + 1] < '0' || str[i + 1] > '9'))
                        {//后面只能出现数字，ch，左括号
                            return false;
                        }
                    }

                    else if (str[i] >= '0' && str[i] <= '9')
                    {//判断数字的前后是否合法

                        if ((str[i - 1] < '0' || str[i - 1] > '9') && str[i - 1] != '+' && str[i - 1] != '-' &&
                            str[i - 1] != '*' && str[i - 1] != '/' && str[i - 1] != '(' && str[i - 1] != '.')
                        {//前面只能是数字，加减乘除和左括号,小数点

                            return false;
                        }
                        if ((str[i + 1] < '0' || str[i + 1] > '9') && str[i + 1] != '+' && str[i + 1] != '-' &&
                            str[i + 1] != '*' && str[i + 1] != '/' && str[i + 1] != ')' && str[i + 1] != '%' && str[i + 1] != '.')
                        {//后面只能是数字，加减乘除，百分号，右括号，小数点
                            return false;
                        }
                    }

                    else if (str[i] == '%')
                    {//判断%前后的数字是否合法

                        if (str[i - 1] < '0' || str[i - 1] > '9')
                        {//前面只能是数字

                            return false;
                        }
                        if (str[i + 1] != '+' && str[i + 1] != '-' && str[i + 1] != '*' && str[i + 1] != '/' && str[i + 1] != ')')
                        {//后面只能是运算符号，右括号

                            return false;
                        }
                    }

                    else if (str[i] == ch)
                    {//判断ch的前后是否合法

                        if (str[i - 1] != '+' && str[i - 1] != '-' && str[i - 1] != '*' && str[i - 1] != '/' && str[i - 1] != '(')
                        {//前面只能是运算符和左括号
                            return false;
                        }
                        if (str[i + 1] != '+' && str[i + 1] != '-' && str[i + 1] != '*' && str[i + 1] != '/' && str[i + 1] != ')')
                        {//后面只能是运算符和右括号
                            return false;
                        }
                    }

                    else if (str[i] == '(')
                    {//判断左括号的前后是否合法
                        bracketCount++;
                        if (str[i - 1] != '+' && str[i - 1] != '-' && str[i - 1] != '*' && str[i - 1] != '/' && str[i - 1] != '(')
                        {//前面只能是运算符和左括号
                            return false;
                        }
                        if ((str[i + 1] < '0' || str[i + 1] > '9') && str[i + 1] != ch)
                        {//后面只能是数字和ch
                            return false;
                        }
                    }

                    else if (str[i] == ')')
                    {//判断右括号的前后是否合法
                        bracketCount--;
                        if ((str[i - 1] < '0' || str[i - 1] > '9') && str[i - 1] != ch && str[i - 1] != '%' && str[i - 1] != ')')
                        {//前面只能是数字，ch，百分号，右括号
                            return false;
                        }
                        if (str[i + 1] != '+' && str[i + 1] != '-' && str[i + 1] != '*' && str[i + 1] != '/' && str[i + 1] != ')')
                        {//后面只能是运算符，右括号
                            return false;
                        }
                    }
                    else if (str[i] == '.')
                    {//判断小数点前后的数据是否合法
                        if (str[i - 1] < '0' || str[i - 1] > '9')
                        {//小数点前面只能是数字
                            return false;
                        }
                        if (str[i + 1] < '0' || str[i + 1] > '9')
                        {//小数点的后面只能是数字

                            return false;
                        }
                    }
                }
                if (bracketCount < 0)
                {
                    return false;
                }
                i++;
            }
            if (bracketCount != 0)
            {
                return false;
            }
            return true;
        }
    }
}
